Game 
Time Limit: 20 Sec Memory Limit: 512 MB
Description 
从前有个游戏。游戏分为 k 轮。
给定一个由小写英文字母组成的字符串的集合 S,
在每轮游戏开始时,双方会得到一个空的字符串,
然后两人轮流在该串的末尾添加字符,并且需要保证新的字符串是 S 中某个串的前缀,直到有一方不能操作,则不能操作的一方输掉这一轮。
新的一轮由上一轮输的人先手,最后一轮赢的人获得游戏胜利。
假定双方都采取最优策略,求第一轮先手的一方能否获胜。
输入包含多组数据。
每组数据的第一行包含两个整数 n,k,分别表示字符串的数量和游戏的轮数。
接下来 n 行,每行一个由小写英文字母组成的字符串。
Output 
对于每组数据输出一行,若先手能获胜输出 HY wins!,否则输出 Teacher wins!
2 3 
  a 
  b 
  3 1 
  a 
  b 
  c
Sample Output 
HY wins! 
  HY wins!
HINT 
1 ≤ n ≤ 1e5,1 ≤ k ≤ 1e9,保证所有字符串长度不超过 1e5,数据组数不超过 10。
Solution 
显然Trie上这个DP显然就是为了求:一轮中,先手是否必胜 或者必败 。显然,一个点如果可以走向必败点 那么就可以必胜 。
Code 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 #include <bits/stdc++.h>  using  namespace  std;typedef  long  long  s64;typedef  unsigned  int  u32;const  int  ONE = 1e6  + 5 ;int  n, k;char  s[ONE];int  next[ONE][27 ], total, root = 1 ;int  f[ONE], g[ONE];int  get ()  {    int  res=1 ,Q=1 ;char  c;     while ( (c=getchar ())<48  || c>57  )         if (c=='-' )Q=-1 ;     res=c-48 ;     while ( (c=getchar ())>=48  && c<=57  )         res=res*10 +c-48 ;     return  res*Q; } void  Insert ()  {    scanf ("%s" , s + 1 );     int  u = root, n = strlen (s + 1 );     for (int  i = 1 ; i <= n; i++)     {         int  c = s[i] - 'a'  + 1 ;         if (!next[u][c]) next[u][c] = ++total;         u = next[u][c];     } } void  Dfs_f (int  u)  {    if (!u) return ;     int  PD = 1 ;     for (int  c = 1 ; c <= 26 ; c++) if (next[u][c]) {PD = 0 ; break ;}     if (PD) {g[u] = 0 ; return ;}     PD = 0 ;     for (int  c = 1 ; c <= 26 ; c++)     {         Dfs_f (next[u][c]);         if (next[u][c] && f[next[u][c]] == 0 ) PD = 1 ;     }     f[u] = PD; } void  Dfs_g (int  u)  {    if (!u) return ;     int  PD = 1 ;     for (int  c = 1 ; c <= 26 ; c++) if (next[u][c]) {PD = 0 ; break ;}     if (PD) {g[u] = 1 ; return ;}     PD = 0 ;     for (int  c = 1 ; c <= 26 ; c++)     {         Dfs_g (next[u][c]);         if (next[u][c] && g[next[u][c]] == 0 ) PD = 1 ;     }     g[u] = PD; } int  main ()  {    while (scanf ("%d %d" , &n, &k) != EOF)     {         memset (f, 0 , sizeof  (f));         memset (g, 0 , sizeof  (g));         memset (next, 0 , sizeof  (next));         total = 1 ;         for (int  i = 1 ; i <= n; i++)             Insert ();         Dfs_f (1 );    Dfs_g (1 );         if (f[1 ] == 1  && g[1 ] == 1 ) printf ("HY wins!\n" );         else              if (f[1 ] == 1 )                 k % 2  == 1  ? printf ("HY wins!\n" ) : printf ("Teacher wins!\n" );         else              printf ("Teacher wins!\n" );     } }